/*******************************************************************************
* @file    fvi2c_mas_signal.h
* @author  Fins
* @brief   I2c signal function file
* @time    2020-10-11 13:51:38 Sunday
* @codeing UTF-8
* @license
*     Copyright 2020 Fins
*
*     Licensed under the Apache License, Version 2.0 (the "License");
*     you may not use this file except in compliance with the License.
*     You may obtain a copy of the License at
*
*         http://www.apache.org/licenses/LICENSE-2.0
*
*     Unless required by applicable law or agreed to in writing, software
*     distributed under the License is distributed on an "AS IS" BASIS,
*     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*     See the License for the specific language governing permissions and
*     limitations under the License.
* @verbatim
================================================================================
                        ##### xxxxxxxxxxxxxxxxxxxxxxx #####
================================================================================
* @endverbatim
* @attention
*******************************************************************************/



/** Prevent recursive inclusion */
#ifndef __FVI2C_MAS_SIGNAL_H
#define __FVI2C_MAS_SIGNAL_H

/** C++ compatible */
#ifdef __cplusplus
 extern "C" {
#endif /** __cplusplus */

/* Includes start *************************************************************/
/*     Lib files ****************************** */
#include "../common/fvi2c_def.h"
#include "../common/fvi2c_config.h"
/*     User files ***************************** */


/* Includes end ***************************************************************/

/* Exported define start ******************************************************/





/* Exported define end ********************************************************/

/* Exported typedef start *****************************************************/





/* Exported typedef end *******************************************************/

/* Exported variable start ****************************************************/





/* Exported variable end ******************************************************/

/* Exported function start ****************************************************/

/**
  * @brief      Delay unit times
  * @param[in]  vi2c: Virtual I2C instance pointer
  * @param[in]  units: Delay time = units * 'UnitDelay()' time
  * @retval     None
  */
F_STATIC_INLINE void Fvi2cMasDelayUnits(fvi2c_s* vi2cP, fuint32 units)
{
    for (fuint32 i = 0; i < units; i++)
    {
        vi2cP->interface.UnitDelay();
    }
}



/**
  * @brief      Wait SCL change to high
  * @param[in]  vi2c: Virtual I2C instance pointer
  * @retval     Refer 'f_vi2cRetStat_e'
  */
F_STATIC_INLINE fvi2c_ret_e Fvi2cMasWaitSclHigh(fvi2c_s* vi2cP)
{
    fuint32 i = FVI2C_WPIN_TIMEOUT;
    while (--i)
    {
        if (vi2cP->interface.GetPin(FVI2C_SCL) == FVI2C_PIN_HIGH)
            return FVI2C_ROK;
    }
    return FVI2C_RTIMEOUT;
}



/**
  * @brief      Transmit start signal
  * @param[in]  vi2c: Virtual I2C instance pointer
  * @retval     Refer 'f_vi2cRetStat_e'
  */
F_STATIC_INLINE fvi2c_ret_e Fvi2cMasTStaSig(fvi2c_s* vi2cP)
{
    /// Is buff free ? 
    if(vi2cP->interface.GetPin(FVI2C_SCL) == FVI2C_PIN_LOW ||
       vi2cP->interface.GetPin(FVI2C_SDA) == FVI2C_PIN_LOW)
        return FVI2C_RBUS_BUSY;
 
    /* hold data stage */
    vi2cP->interface.SetPin(FVI2C_SDA, FVI2C_PIN_LOW);/// SDA ↓
    Fvi2cMasDelayUnits(vi2cP,vi2cP->conf.holdPosTime);
    vi2cP->interface.SetPin(FVI2C_SCL, FVI2C_PIN_LOW);/// SCL ↓
    return FVI2C_ROK;
}



/**
  * @brief      Transmit restart signal
  * @param[in]  vi2c: Virtual I2C instance pointer
  * @retval     Refer 'f_vi2cRetStat_e'
  */
F_STATIC_INLINE fvi2c_ret_e Fvi2cMasTRestaSig(fvi2c_s* vi2cP)
{
    fvi2c_ret_e ret;
    /* change data stage */
    Fvi2cMasDelayUnits(vi2cP,vi2cP->conf.chgPerTime);
    vi2cP->interface.SetPin(FVI2C_SDA, FVI2C_PIN_HIGH);/// SDA ↑
    Fvi2cMasDelayUnits(vi2cP,vi2cP->conf.chgPosTime);
    vi2cP->interface.SetPin(FVI2C_SCL, FVI2C_PIN_HIGH);/// SCL ↑
    /* wait SCL high */
    ret = Fvi2cMasWaitSclHigh(vi2cP);
    if(ret != FVI2C_ROK) return ret;

    /* Arbitrate */
    if(vi2cP->interface.GetPin(FVI2C_SDA) != FVI2C_PIN_HIGH)
    {   /* Arbitrate fail release bus */
        vi2cP->interface.SetPin(FVI2C_SDA, FVI2C_PIN_HIGH);/// SDA ↑
        vi2cP->interface.SetPin(FVI2C_SCL, FVI2C_PIN_HIGH);/// SCL ↑
        return FVI2C_RARB_FAIL;
    }
        

    /* hold data stage */
    Fvi2cMasDelayUnits(vi2cP,vi2cP->conf.holdPerTime);
    vi2cP->interface.SetPin(FVI2C_SDA, FVI2C_PIN_LOW);/// SDA ↓
    Fvi2cMasDelayUnits(vi2cP,vi2cP->conf.holdPosTime);
    vi2cP->interface.SetPin(FVI2C_SCL, FVI2C_PIN_LOW);/// SCL ↓
    return FVI2C_ROK;
}



/**
  * @brief      Transmit stop signal
  * @param[in]  vi2c: Virtual I2C instance pointer
  * @retval     Refer 'f_vi2cRetStat_e'
  */
F_STATIC_INLINE fvi2c_ret_e Fvi2cMasTStopSig(fvi2c_s* vi2cP)
{
    fvi2c_ret_e ret;
    /* change data stage */
    Fvi2cMasDelayUnits(vi2cP,vi2cP->conf.chgPerTime);
    vi2cP->interface.SetPin(FVI2C_SDA, FVI2C_PIN_LOW);/// SDA ↓
    Fvi2cMasDelayUnits(vi2cP,vi2cP->conf.chgPosTime);
    vi2cP->interface.SetPin(FVI2C_SCL, FVI2C_PIN_HIGH);/// SCL ↑
    /* wait SCL high */
    ret = Fvi2cMasWaitSclHigh(vi2cP);
    if(ret != FVI2C_ROK) return ret;

    /* Arbitrate */
    if(vi2cP->interface.GetPin(FVI2C_SDA) != FVI2C_PIN_LOW)
    {   /* Arbitrate fail release bus */
        vi2cP->interface.SetPin(FVI2C_SDA, FVI2C_PIN_HIGH);/// SDA ↑
        vi2cP->interface.SetPin(FVI2C_SCL, FVI2C_PIN_HIGH);/// SCL ↑
        return FVI2C_RARB_FAIL;
    }

    /* hold data stage */
    Fvi2cMasDelayUnits(vi2cP,vi2cP->conf.holdPerTime);
    vi2cP->interface.SetPin(FVI2C_SDA, FVI2C_PIN_HIGH);/// SDA ↑
    Fvi2cMasDelayUnits(vi2cP,vi2cP->conf.holdPosTime);
    return FVI2C_ROK;
}



/**
  * @brief      Transmit bit
  * @param[in]  vi2c: Virtual I2C instance pointer
  * @param[in]  bit: 0 or 1
  * @retval     Refer 'f_vi2cRetStat_e'
  */
F_STATIC_INLINE fvi2c_ret_e Fvi2cMasTBit(fvi2c_s* vi2cP,fuint8 bit)
{
    fvi2c_ret_e ret;
    /* change data stage */
    Fvi2cMasDelayUnits(vi2cP,vi2cP->conf.chgPerTime);
    vi2cP->interface.SetPin(FVI2C_SDA, (fvi2c_pSta_e)bit);/// SDA
    Fvi2cMasDelayUnits(vi2cP,vi2cP->conf.chgPosTime);
    vi2cP->interface.SetPin(FVI2C_SCL, FVI2C_PIN_HIGH);/// SCL ↑
    /* wait SCL high */
    ret = Fvi2cMasWaitSclHigh(vi2cP);
    if(ret != FVI2C_ROK) return ret;

    /* Arbitrate */
    if(vi2cP->interface.GetPin(FVI2C_SDA) != (fvi2c_pSta_e)bit)
    {   /* Arbitrate fail release bus */
        vi2cP->interface.SetPin(FVI2C_SDA, FVI2C_PIN_HIGH);/// SDA ↑
        vi2cP->interface.SetPin(FVI2C_SCL, FVI2C_PIN_HIGH);/// SCL ↑
        return FVI2C_RARB_FAIL;
    }

    /* hold data stage */
    Fvi2cMasDelayUnits(vi2cP,vi2cP->conf.holdPerTime);
    Fvi2cMasDelayUnits(vi2cP,vi2cP->conf.holdPosTime);
    vi2cP->interface.SetPin(FVI2C_SCL, FVI2C_PIN_LOW);/// SCL ↓
    return FVI2C_ROK;
}



/**
  * @brief      Recieve bit
  * @param[in]  vi2c: Virtual I2C instance pointer
  * @param[out] bit: 0 or 1
  * @retval     Refer 'f_vi2cRetStat_e'
  */
F_STATIC_INLINE fvi2c_ret_e Fvi2cMasRBit(fvi2c_s* vi2cP,fuint8* bit)
{
    fvi2c_ret_e ret;

    /* change data stage */
    Fvi2cMasDelayUnits(vi2cP,vi2cP->conf.chgPerTime);
    vi2cP->interface.SetPin(FVI2C_SDA, FVI2C_PIN_HIGH);/// SDA ↑ release SDA
    Fvi2cMasDelayUnits(vi2cP,vi2cP->conf.chgPosTime);
    vi2cP->interface.SetPin(FVI2C_SCL, FVI2C_PIN_HIGH);/// SCL ↑
    /* wait SCL high */
    ret = Fvi2cMasWaitSclHigh(vi2cP);
    if(ret != FVI2C_ROK) return ret;

    /* hold data stage */
    Fvi2cMasDelayUnits(vi2cP,vi2cP->conf.holdPerTime);
    *bit = vi2cP->interface.GetPin(FVI2C_SDA);/// Get SDA
    Fvi2cMasDelayUnits(vi2cP,vi2cP->conf.holdPosTime);
    vi2cP->interface.SetPin(FVI2C_SCL, FVI2C_PIN_LOW);/// SCL ↓
    return FVI2C_ROK;
}

/* Exported function end ******************************************************/

/** C++ compatible */
#ifdef __cplusplus
}
#endif /** __cplusplus */

#endif /** __FVI2C_MAS_SIGNAL_H */
////////////////////////////////- END OF FILE  -////////////////////////////////